home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 14 / Mac Magazin and MacEasy Magazine CD - Issue 14.iso / Utilities / Grabbug1.0b2 Folder / Source / GrabbugCommon.p next >
Encoding:
Text File  |  1995-08-24  |  11.8 KB  |  402 lines  |  [TEXT/MWPS]

  1. unit GrabbugCommon;
  2.  
  3. (* ©1995 Quinn "The Eskimo!" *)
  4. (* This file is distributed as Freeware. *)
  5.  
  6. interface
  7.  
  8.     uses
  9.         Types;
  10.     
  11.     const
  12.         noDcmdErr = -6660;
  13.         screenSizeChangedErr = -6661;
  14.         noMainGDeviceErr = -6662;
  15.         noGrabErr = -6663;
  16.         screenSizeChangedErr2 = -6664;
  17.         
  18.     const
  19.         gestaltGrabbugVariables = 'Gräb';
  20.         grabbug_creator = 'Gräb';
  21.  
  22.     (* The following routines are used by the dcmd. *)
  23.     
  24.     function DoInit(var refcon : longint) : OSErr;
  25.     function DoGrab(refcon : longint) : OSErr;
  26.     procedure DoTerm(refcon : longint);
  27.  
  28.     (* The following routine is used by Grabbug Dump. *)
  29.     
  30.     function DoDump : OSErr;
  31.  
  32. implementation
  33.  
  34.     uses
  35.         Files,
  36.         Memory,
  37.         QuickDraw,
  38.         QDOffscreen,
  39.         TextUtils,
  40.         LowMem,
  41.         GestaltEqu;
  42.  
  43. (* ***** Utilities copied out of my libraries ***** *)
  44.  
  45.     procedure UniqueFileName(prefix : Str255; var fss : FSSpec);
  46.         var
  47.             err : OSErr;
  48.             attempt : integer;
  49.             filename : Str255;
  50.     begin
  51.         attempt := 0;
  52.         repeat
  53.             NumToString(attempt, filename);
  54.             filename := concat(prefix, filename);
  55.             err := FSMakeFSSpec(-1, 2, filename, fss);
  56.             attempt := attempt + 1;
  57.         until (err = fnfErr) or (attempt > 1000);
  58.     end; (* UniqueFileName *)
  59.     
  60.     function FSWriteQ(refnum : integer; count : longint; buf : univ Ptr) : OSErr;
  61.     begin
  62.         FSWriteQ := FSWrite(refnum, count, buf);
  63.     end; (* FSWriteQ *)
  64.  
  65.     procedure BlockClear(dest : univ Ptr; size : longint);
  66.         type
  67.             memBlock = packed array [0..16000000] of byte;
  68.             memBlockPtr = ^memBlock;
  69.         var
  70.             i : longint;
  71.             tmpdest : memBlockPtr;
  72.     begin
  73.         tmpdest := memBlockPtr(dest);
  74.         for i := 0 to size - 1 do begin
  75.             tmpdest^[i] := 0;
  76.         end; (* for *)
  77.     end; (* BlockClear *)
  78.  
  79. (* **** Common bits **** *)
  80.  
  81.     function GetMainScreenInfo(var pm_base : Ptr; var pm_32bit : boolean; var pm_rowbytes : integer; var pm_size : longint) : OSErr;
  82.         (* Gets various attributes about the main display.  This routine peers inside
  83.             structures rather than using the defined API because I anticipate that
  84.                 it will be called at all sorts of odd times.
  85.         *)
  86.         var
  87.             err : OSErr;
  88.             main_gd : GDHandle;
  89.             gdpm : PixMapHandle;
  90.     begin
  91.         err := noErr;
  92.         main_gd := LMGetMainDevice;
  93.         if main_gd = nil then begin
  94.             err := noMainGDeviceErr;
  95.         end; (* if *)
  96.         if err = noErr then begin
  97.             gdpm := main_gd^^.gdPMap;
  98.             pm_32bit := PixMap32Bit(gdpm);    (* some disassembly reveals that it's reasonably safe to call this (: *)
  99.             pm_base := gdpm^^.baseAddr;
  100.             pm_rowbytes := band(gdpm^^.rowBytes, $3FFF);
  101.             pm_size := longint(pm_rowbytes) * (gdpm^^.bounds.bottom - gdpm^^.bounds.top);
  102.         end; (* if *)
  103.         GetMainScreenInfo := err;
  104.     end; (* GetMainScreenInfo *)
  105.  
  106.     (* The globals record pointed to by the Gestalt selector. *)
  107.     
  108.     type
  109.         myGlobals = record
  110.             signature : OSType;
  111.             version : integer;
  112.             have_grabbed : boolean;
  113.             screen_rowbytes : integer;
  114.             screen_buffer : Ptr;
  115.             screen_buffer_size : longint;
  116.         end;
  117.         myGlobalsPtr = ^myGlobals;
  118.  
  119. (* **** These bits slated for the application ***** *)
  120.         
  121.     function CreateOpenPictureFile(fss : FSSpec; var ref : integer) : OSErr;
  122.         (* Create a picture file, open it and write out the 512 bytes of zeros
  123.                 which make up the header.
  124.         *)
  125.         var
  126.             err : OSErr;
  127.             header : packed array [0..511] of byte;
  128.     begin
  129.         ref := 0;
  130.         err := FSpCreate(fss, 'ttxt', 'PICT', 0);
  131.         if err = noErr then begin
  132.             err := FSpOpenDF(fss, fsRdWrPerm, ref);
  133.         end; (* if *)
  134.         if err = noErr then begin
  135.             BlockClear(@header, sizeof(header));
  136.             err := FSWriteQ(ref, sizeof(header), @header);
  137.         end; (* if *)
  138.         CreateOpenPictureFile := err;
  139.     end; (* CreateOpenPictureFile *)
  140.  
  141.     (* ----- The PutPic Engine ----- *)
  142.     
  143.     (* The PutPic engine is a replacement for QuickDraw's StdPutPic proc that
  144.             spools the file into a PICT file instead of into the picture. There
  145.             are initialisation and termination procedures that setup and shutdown
  146.             the engine, and a replacement for the QuickDraw bottleneck.
  147.     *)
  148.     
  149.     (* Some state variables for the PutPic engine. *)
  150.     
  151.     var
  152.         myputpic_err : OSErr;                        (* a sticky error code *)
  153.         myputpic_ref : integer;                    (* dest file refnum *)
  154.  
  155.     procedure MyPutPic(data : Ptr; size : integer);
  156.         (* A replacement for QuickDraw's StdPutPic. *)
  157.     begin
  158.         if myputpic_err = noErr then begin
  159.             myputpic_err := FSWriteQ(myputpic_ref, size, data);
  160.         end; (* if *)
  161.     end; (* MyPutPic *)
  162.  
  163.     procedure InitMyPutPic(var mycqdprocs : CQDProcs; ref : integer);
  164.         (* Initialise the PutPic engine. *)
  165.     begin
  166.         SetStdCProcs(mycqdprocs);
  167.         mycqdprocs.putPicProc := @MyPutPic;
  168.         CGrafPtr(qd.thePort)^.grafProcs := @mycqdprocs;
  169.         myputpic_err := noErr;
  170.         myputpic_ref := ref;
  171.     end; (* InitMyPutPic *)
  172.         
  173.     function TermMyPutPic(picth : PicHandle; ref : integer) : OSErr;
  174.         (* Shut down the PutPic engine, most importantly
  175.             write the final picture header into the right place in the file.
  176.         *)
  177.     begin
  178.         if GetHandleSize(Handle(picth)) <> 10 then begin
  179.             DebugStr('Fatal assumption failure.');
  180.         end; (* if *)
  181.         (* write the final picture header into the right place in the file *)
  182.         if myputpic_err = noErr then begin
  183.             myputpic_err := SetFPos(ref, fsFromStart, 512);
  184.         end; (* if *)
  185.         MyPutPic(Ptr(picth^), 10);
  186.         TermMyPutPic := myputpic_err;
  187.     end; (* TermMyPutPic *)
  188.  
  189.     function DoDump : OSErr;
  190.         (* Dump the captured screen to a new PICT file on the disk. *)
  191.         
  192.         function SpoolPicture(dcmd_globals : myGlobalsPtr; ref : integer) : OSErr;
  193.             (* Creates an offscreen GWorld and copies the captured screen data into
  194.                     it, having set up to spool the resulting PICT to a file.
  195.                This routine is pretty slack about cleaning up, simply because we expect to
  196.                     clean up at application termination time.
  197.             *)
  198.             var
  199.                 err : OSErr;
  200.                 gworld : GWorldPtr;
  201.                 screen_rect : Rect;
  202.                 picth : PicHandle;
  203.                 src_pixmap : PixMapHandle;
  204.                 junk_bool : boolean;
  205.                 mycqdprocs : CQDProcs;
  206.         begin
  207.             (* create an offscreen GWorld *)
  208.             (* and make a pixmap out of the screen_buffer *)
  209.             err := noErr;
  210.             if err = noErr then begin
  211.                 err := NewGWorld(gworld, 0, GetMainDevice^^.gdPMap^^.bounds, nil, nil, noNewDevice);
  212.             end; (* if *)
  213.             if err = noErr then begin
  214.                 SetGWorld(gworld, nil);
  215.                 junk_bool := LockPixels(GetGWorldPixMap(gworld));
  216.                 src_pixmap := NewPixMap;
  217.                 if src_pixmap = nil then begin
  218.                     err := memFullErr;
  219.                 end; (* if *)
  220.             end; (* if *)
  221.             if err = noErr then begin
  222.                 CopyPixMap(GetMainDevice^^.gdPMap, src_pixmap);                (* gets the colour table correct *)
  223.                 HLock(Handle(src_pixmap));
  224.                 src_pixmap^^.baseAddr := dcmd_globals^.screen_buffer;    (* point it at the dcmd's buffer *)
  225.                 screen_rect := GrafPtr(gworld)^.portRect;
  226.                 (* setup PutPic procedure *)
  227.                 InitMyPutPic(mycqdprocs, ref);                                                (* prepare for spooling *)
  228.                 (* spool the bitmap into a picture *)
  229.                 picth := OpenPicture(screen_rect);
  230.                 MyPutPic(Ptr(picth^), 10);                                                        (* write the bogus header *)
  231.                 ClipRect(GrafPtr(gworld)^.portRect);
  232.                 CopyBits(BitMapPtr(src_pixmap^)^, GrafPtr(gworld)^.portBits, screen_rect, screen_rect, srcCopy, nil);
  233.                 err := QDError;
  234.                 ClosePicture;
  235.             end; (* if *)
  236.             if err = noErr then begin
  237.                 err := TermMyPutPic(picth, ref);                                            (* shut down spool *)
  238.             end; (* if *)
  239.             SpoolPicture := err;
  240.         end; (* SpoolPicture *)
  241.  
  242.         var
  243.             err : OSErr;
  244.             err2 : OSErr;
  245.             dcmd_globals : myGlobalsPtr;
  246.             fss : FSSpec;
  247.             ref : integer;
  248.             junk_bool : boolean;
  249.             junk_ptr : Ptr;
  250.             pm_rowbytes : integer;
  251.             pm_size : longint;
  252.     begin
  253.         (* look up dcmd's globals *)
  254.         err := Gestalt(gestaltGrabbugVariables, longint(dcmd_globals));
  255.         if err = gestaltUndefSelectorErr then begin
  256.             err := noDcmdErr;
  257.         end; (* if *)
  258.         (* check that the dcmd's state is compatible *)
  259.         if err = noErr then begin
  260.             if not dcmd_globals^.have_grabbed then begin
  261.                 err := noGrabErr;
  262.             end; (* if *)
  263.         end; (* if *)
  264.         if err = noErr then begin
  265.             err := GetMainScreenInfo(junk_ptr, junk_bool, pm_rowbytes, pm_size);
  266.             if (err = noErr) and
  267.                         ((pm_rowbytes <> dcmd_globals^.screen_rowbytes) or
  268.                          (pm_size <> dcmd_globals^.screen_buffer_size)) then begin
  269.                 err := screenSizeChangedErr2
  270.             end; (* if *)
  271.         end; (* if *)
  272.         (* create and open the PICT file *)
  273.         if err = noErr then begin
  274.             UniqueFileName('Grabbug ', fss);
  275.             err := CreateOpenPictureFile(fss, ref);
  276.         end; (* if *)
  277.         if err = noErr then begin
  278.             err := SpoolPicture(dcmd_globals, ref);
  279.         end; (* if *)
  280.         (* clean up *)
  281.         if ref <> 0 then begin    
  282.             err2 := FSClose(ref);
  283.             if err = noErr then begin
  284.                 err := err2;
  285.             end; (* if *)
  286.         end; (* if *)
  287.         DoDump := err;
  288.     end; (* DoDump *)
  289.     
  290. (* **** These bits slated for the dcmd **** *)
  291.  
  292. (* These headers for copied out of GestaltEqu.p otherwise I would have
  293.         had to engage System 7.5 or later, which would have required me
  294.         to recompile CW's pre-compiled header, which I didn't have the disk
  295.         space to do!
  296. *)
  297.  
  298. { These functions are built into System 7.5, but not on earlier systems }
  299. FUNCTION NewGestaltValue(selector: OSType; newValue: LONGINT): OSErr;
  300.     {$IFC NOT GENERATINGCFM}
  301.     INLINE $303C, $0401, $ABF1;
  302.     {$ENDC}
  303. FUNCTION ReplaceGestaltValue(selector: OSType; replacementValue: LONGINT): OSErr;
  304.     {$IFC NOT GENERATINGCFM}
  305.     INLINE $303C, $0402, $ABF1;
  306.     {$ENDC}
  307. FUNCTION SetGestaltValue(selector: OSType; newValue: LONGINT): OSErr;
  308.     {$IFC NOT GENERATINGCFM}
  309.     INLINE $303C, $0404, $ABF1;
  310.     {$ENDC}
  311. FUNCTION DeleteGestaltValue(selector: OSType): OSErr;
  312.     {$IFC NOT GENERATINGCFM}
  313.     INLINE $303C, $0203, $ABF1;
  314.     {$ENDC}
  315.  
  316.     function DoInit(var refcon : longint) : OSErr;
  317.         (* Initialises the dcmd, first creating and registering its globals
  318.                 and then creating the screen capture buffer.
  319.         *)
  320.         var
  321.             err : OSErr;
  322.             my_globals : myGlobalsPtr;
  323.             pm_base : Ptr;
  324.             pm_32bit : boolean;
  325.     begin
  326.         err := noErr;
  327.         (* create and initialise the globals and register them with Gestalt *)
  328.         my_globals := myGlobalsPtr(NewPtrSys(sizeof(myGlobals)));
  329.         refcon := longint(my_globals);
  330.         if my_globals = nil then begin
  331.             err := memFullErr;
  332.         end; (* if *)
  333.         if err = noErr then begin
  334.             my_globals^.signature := gestaltGrabbugVariables;
  335.             my_globals^.version := 0;
  336.             my_globals^.have_grabbed := false;
  337.             my_globals^.screen_rowbytes := 0;
  338.             my_globals^.screen_buffer := nil;
  339.             my_globals^.screen_buffer_size := 0;
  340.             err := NewGestaltValue(gestaltGrabbugVariables, longint(my_globals))
  341.         end; (* if *)
  342.         (* create the screen capture buffer *)
  343.         if err = noErr then begin
  344.             err := GetMainScreenInfo(pm_base, pm_32bit, my_globals^.screen_rowbytes, my_globals^.screen_buffer_size);
  345.             if err = noErr then begin
  346.                 my_globals^.screen_buffer := NewPtrSys(my_globals^.screen_buffer_size);
  347.                 err := MemError;
  348.             end; (* if *)
  349.         end; (* if *)
  350.         DoInit := err;
  351.     end; (* DoInit *)
  352.  
  353.     function DoGrab(refcon : longint) : OSErr;
  354.         (* Capture the screen by copying it to the screen buffer. *)
  355.         var
  356.             my_globals : myGlobalsPtr;
  357.             err : OSErr;
  358.             mmu_mode : SInt8;
  359.             pm_base : Ptr;
  360.             pm_32bit : boolean;
  361.             pm_rowbytes : integer;
  362.             pm_size : longint;
  363.     begin
  364.         my_globals := myGlobalsPtr(refcon);
  365.         err := GetMainScreenInfo(pm_base, pm_32bit, pm_rowbytes, pm_size);
  366.         if err = noErr then begin
  367.             if (pm_size <> my_globals^.screen_buffer_size)
  368.                     or (pm_rowbytes <> my_globals^.screen_rowbytes) then begin
  369.                 err := screenSizeChangedErr;
  370.             end; (* if *)
  371.         end; (* if *)
  372.         if err = noErr then begin
  373.             if pm_32bit then begin
  374.                 mmu_mode := true32b;
  375.                 SwapMMUMode(mmu_mode);
  376.             end; (* if *)
  377.             BlockMove(pm_base, my_globals^.screen_buffer, my_globals^.screen_buffer_size);
  378.             if pm_32bit then begin
  379.                 SwapMMUMode(mmu_mode);
  380.             end; (* if *)
  381.             my_globals^.have_grabbed := true;
  382.         end; (* if *)
  383.         DoGrab := err;
  384.     end; (* DoGrab *)
  385.     
  386.     procedure DoTerm(refcon : longint);
  387.         (* Terminate the dcmd, clean up the globals. *)
  388.         var
  389.             junk : OSErr;
  390.             my_globals : myGlobalsPtr;
  391.     begin
  392.         my_globals := myGlobalsPtr(refcon);
  393.         junk := DeleteGestaltValue(gestaltGrabbugVariables);
  394.         if (my_globals <> nil) & (my_globals^.screen_buffer <> nil) then begin
  395.             DisposePtr(my_globals^.screen_buffer);
  396.         end; (* if *)
  397.         if my_globals <> nil then begin
  398.             DisposePtr(Ptr(my_globals));
  399.         end; (* if *)
  400.     end; (* DoTerm *)
  401.     
  402. end. (* GrabbugCommon *)